﻿using Newtonsoft.Json;
using System.Diagnostics;
using System.Drawing;
using VisionDesigner;
using VisionDesigner.HPFeaturePatMatch;
using VM.Common.Enums;
using VM.Common.Helper;
using VM.Start.Common.Hik;
using VM.Start.Common.Provide;
using VM.Start.Controls;

namespace Plugin.Matching
{

    #region enum
    public enum eSelectImageCommand
    {
        LocalImage,
        OtherImage
    }

    #endregion

    [JsonObject(MemberSerialization.OptOut)]
    public class EditViewModel : NotifyPropertyBase
    {
        #region  属性

        [Newtonsoft.Json.JsonIgnore]
        public MatchingViewModel matchingViewModel;
        [Newtonsoft.Json.JsonIgnore]
        public EditView view;
        [Newtonsoft.Json.JsonIgnore]
        public CMvdImage LocalImage;
        #region 训练图像
        public uint Width;
        public uint Height;
        public MVD_PIXEL_FORMAT PIXEL_FORMAT = MVD_PIXEL_FORMAT.MVD_PIXEL_NULL;
        public MVD_IMAGE_DATA_INFO ImageData = null;
        [Newtonsoft.Json.JsonIgnore]
        private CMvdImage _TrainImage;
        [Newtonsoft.Json.JsonIgnore]
        public CMvdImage TrainImage
        {
            get
            {
                if ((_TrainImage == null || _TrainImage.IsEmpty) &&
                    ImageData != null && ImageData.stDataChannel[0].arrDataBytes != null &&
                    Width != 0 && Height != 0 && PIXEL_FORMAT != MVD_PIXEL_FORMAT.MVD_PIXEL_NULL)
                {
                    _TrainImage = new CMvdImage();
                    _TrainImage.InitImage(Width, Height, PIXEL_FORMAT, ImageData);
                }
                return _TrainImage;
            }
            set
            {
                _TrainImage = value;
                if (_TrainImage != null && !_TrainImage.IsEmpty)
                {
                    Width = _TrainImage.Width;
                    Height = _TrainImage.Height;
                    PIXEL_FORMAT = _TrainImage.PixelFormat;
                    ImageData = _TrainImage.GetImageData();
                }
                else
                {
                    Width = 0;
                    Height = 0;
                    PIXEL_FORMAT = MVD_PIXEL_FORMAT.MVD_PIXEL_NULL;
                    ImageData = null;
                }
                LearnMatch.Image = value;
            }
        }
        #endregion
        #region 训练结果图像
        public uint rWidth;
        public uint rHeight;
        public MVD_PIXEL_FORMAT rPIXEL_FORMAT = MVD_PIXEL_FORMAT.MVD_PIXEL_NULL;
        public MVD_IMAGE_DATA_INFO rImageData = null;
        [Newtonsoft.Json.JsonIgnore]
        private CMvdImage _rTrainImage;
        [Newtonsoft.Json.JsonIgnore]
        private CMvdImage rTrainImage
        {
            get
            {
                if ((_rTrainImage == null || _rTrainImage.IsEmpty) &&
                    rImageData != null && rImageData.stDataChannel[0].arrDataBytes != null &&
                    rWidth != 0 && rHeight != 0 && rPIXEL_FORMAT != MVD_PIXEL_FORMAT.MVD_PIXEL_NULL)
                {
                    _rTrainImage = new CMvdImage();
                    _rTrainImage.InitImage(rWidth, rHeight, rPIXEL_FORMAT, rImageData);
                }
                return _rTrainImage;
            }
            set
            {
                _rTrainImage = value;
                if (_rTrainImage != null && !_rTrainImage.IsEmpty)
                {
                    rWidth = _rTrainImage.Width;
                    rHeight = _rTrainImage.Height;
                    rPIXEL_FORMAT = _rTrainImage.PixelFormat;
                    rImageData = _rTrainImage.GetImageData();
                }
                else
                {
                    rWidth = 0;
                    rHeight = 0;
                    rPIXEL_FORMAT = MVD_PIXEL_FORMAT.MVD_PIXEL_NULL;
                    rImageData = null;
                }
                TemplateWindow.Image = value;
            }
        }
        #endregion
        [Newtonsoft.Json.JsonIgnore]
        public TemplateModel m_TemplateModel;

        private Stopwatch _StopWatch = new Stopwatch();

        public byte[] ModelData;
        public ulong ModelSize;
        private CHPFeaturePattern _hpFeaturePattern;
        // 定义 HPFeaturePattern 属性
        public CHPFeaturePattern HPFeaturePattern
        {
            get
            {
                if (_hpFeaturePattern != null && _hpFeaturePattern.ModelData == null
                    && ModelData != null && ModelSize != 0)
                {
                    _hpFeaturePattern.ImportPattern(ModelData, ModelSize);
                    _hpFeaturePattern.InputImage = TrainImage;
                }
                return _hpFeaturePattern;
            }
            set
            {
                if (_hpFeaturePattern != value)
                {
                    _hpFeaturePattern = value;
                    if (_hpFeaturePattern.InputImage != null && !_hpFeaturePattern.InputImage.IsEmpty)
                    {
                        LearnMatch.Image = _hpFeaturePattern.InputImage;
                    }
                    if (_hpFeaturePattern != null && _hpFeaturePattern.Result != null)
                    {
                        var patternData = HPFeaturePattern.Result.Data;
                        Param.ParamDouble["速度尺度"] = patternData.Rough;
                        Param.ParamInt["特征尺度"] = Convert.ToInt32(patternData.Fine);
                        Param.ParamInt["对比度阈值"] = patternData.LowThreshold;
                        DisplayTrainedImageAndOutline(TemplateWindow);
                    }
                }
            }
        }

        public List<CMvdPointSetF> _PatternOutlineList = new List<CMvdPointSetF>();    // 模型轮廓点集
        #endregion
        #region  数据接口
        [Newtonsoft.Json.JsonIgnore]
        public VMDisplayControl _LearnMatch;
        [Newtonsoft.Json.JsonIgnore]
        public VMDisplayControl LearnMatch
        {
            get
            {
                if (_LearnMatch == null)
                {
                    _LearnMatch = new VMDisplayControl();
                }
                return _LearnMatch;
            }
        }

        [Newtonsoft.Json.JsonIgnore]
        private VMDisplayControl _TemplateWindow;
        [Newtonsoft.Json.JsonIgnore]
        public VMDisplayControl TemplateWindow
        {
            get
            {
                if (_TemplateWindow == null)
                {
                    _TemplateWindow = new VMDisplayControl();
                }
                return _TemplateWindow;
            }
        }
        /// <summary>
        /// 参数
        /// </summary>
        public TemplateParamModel Param { get; set; } = new TemplateParamModel();
        /// <summary>
        /// 指定ROI
        /// </summary>
        public CMvdShape ROI;
        public Point MatchPoint;
        public ROITypeEnum _EditROIMode = ROITypeEnum.全图;
        public ROITypeEnum EditROIMode
        {
            get { return _EditROIMode; }
            set
            {
                Set(ref _EditROIMode, value, new Action(() =>
                {
                    LearnMatch.ROI = ROI;
                    switch (_EditROIMode)
                    {
                        case ROITypeEnum.全图:
                            LearnMatch.ROIType = ROITypeEnum.全图;
                            break;
                        case ROITypeEnum.矩形:
                            LearnMatch.ROIType = ROITypeEnum.矩形;
                            break;
                        case ROITypeEnum.圆:
                            LearnMatch.ROIType = ROITypeEnum.圆;
                            break;
                        default:
                            break;
                    }
                }));
            }
        }
        #endregion
        #region  指令
        [Newtonsoft.Json.JsonIgnore]
        private CommandBase _SelectImageCommand;
        [Newtonsoft.Json.JsonIgnore]
        public CommandBase SelectImageCommand
        {
            get
            {
                if (_SelectImageCommand == null)
                {
                    _SelectImageCommand = new CommandBase(
                        (obj) =>
                        {
                            try
                            {
                                eSelectImageCommand par = (eSelectImageCommand)obj;
                                switch (par)
                                {
                                    case eSelectImageCommand.LocalImage:
                                        TrainImage = LocalImage;
                                        break;
                                    case eSelectImageCommand.OtherImage:
                                        Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
                                        dlg.Filter = "所有图像文件 | *.bmp; *.pcx; *.png; *.jpg; *.gif;*.tif; *.ico; *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf";
                                        if (dlg.ShowDialog() == true)
                                        {
                                            RImage rImage = new RImage();
                                            rImage.InitImage(dlg.FileName, VisionDesigner.MVD_PIXEL_FORMAT.MVD_PIXEL_MONO_08);
                                            TrainImage = rImage;
                                        }
                                        break;
                                    default:
                                        throw new ArgumentOutOfRangeException();
                                }
                            }
                            catch (Exception ex)
                            {

                            }
                        }
                    );
                }
                return _SelectImageCommand;
            }
        }

        [Newtonsoft.Json.JsonIgnore]
        private CommandBase _learnCommand;
        [Newtonsoft.Json.JsonIgnore]
        public CommandBase LearnCommand
        {
            get
            {
                if (_learnCommand == null)
                {
                    _learnCommand = new CommandBase((obj) =>
                    {
                        CreateModel();
                    });
                }
                return _learnCommand;
            }
        }

        [Newtonsoft.Json.JsonIgnore]
        private CommandBase _ConfirmCommand;
        [Newtonsoft.Json.JsonIgnore]
        public CommandBase ConfirmCommand
        {
            get
            {
                if (_ConfirmCommand == null)
                {
                    _ConfirmCommand = new CommandBase((obj) =>
                    {
                        if (view != null)
                        {
                            CreateModel();
                            if (m_TemplateModel == null)
                            {
                                m_TemplateModel = new TemplateModel();

                                // 确保新模板的名称唯一
                                string baseName = "新建模板";
                                int index = 1;
                                string newName;

                                // 循环检查名称是否已存在
                                do
                                {
                                    newName = $"{baseName}{index}";
                                    index++;
                                } while (matchingViewModel.TemplateList.Any(template => template.Name == newName));

                                m_TemplateModel.Name = newName;
                                m_TemplateModel.Index = matchingViewModel.TemplateList.Count;
                                matchingViewModel.TemplateList.Add(m_TemplateModel);
                            }
                            m_TemplateModel.Data = this;
                            matchingViewModel.SelectedTemplate = m_TemplateModel;
                            view.Close();
                        }
                    });
                }
                return _ConfirmCommand;
            }
        }

        #endregion
        #region  方法
        public void Loaded()
        {
            if (TrainImage != null && !TrainImage.IsEmpty)
            {
                LearnMatch.Image = TrainImage;
            }
            if (rTrainImage != null && !rTrainImage.IsEmpty)
            {
                TemplateWindow.Image = rTrainImage;
                TemplateWindow.MVDRender.Display(MVDRenderActivex.MVD_REFRESH_MODE.Sync);
                TemplateWindow.DrawPointSetFList(_PatternOutlineList);
            }
        }

        /// <summary>
        /// 处理 HPFeaturePattern 设置时的初始化逻辑的方法
        /// </summary>
        private void OnHPFeaturePatternChanged()
        {
            List<CPatMatchRegion> DrawRegionList = new List<CPatMatchRegion>();
            foreach (var region in HPFeaturePattern.RegionList)
            {
                var item = new CPatMatchRegion();
                switch (region.Shape.ShapeType)
                {
                    // 矩形
                    case MVD_SHAPE_TYPE.MvdShapeRectangle:
                        {
                            var regionShape = region.Shape as CMvdRectangleF;
                            regionShape.Interaction = false;
                            item.Shape = regionShape.Clone() as CMvdRectangleF;
                        }
                        break;
                    // 扇环
                    case MVD_SHAPE_TYPE.MvdShapeAnnularSector:
                        {
                            var regionShape = region.Shape as CMvdAnnularSectorF;
                            regionShape.Interaction = false;
                            item.Shape = regionShape.Clone() as CMvdAnnularSectorF;
                        }
                        break;
                    // 多边形
                    case MVD_SHAPE_TYPE.MvdShapePolygon:
                        {
                            var regionShape = region.Shape as CMvdPolygonF;
                            regionShape.Interaction = false;
                            item.Shape = regionShape.Clone() as CMvdPolygonF;
                        }
                        break;
                    default:
                        {
                            throw new MvdException(MVD_MODULE_TYPE.MVD_MODUL_APP, MVD_ERROR_CODE.MVD_E_PARAMETER_ILLEGAL);
                        }
                }
                item.Sign = region.Sign;
                DrawRegionList.Add(item);
                LearnMatch.AddShape(item.Shape);
            }
        }

        public void CreateModel()
        {
            try
            {
                if ((null == HPFeaturePattern) || (null == LearnMatch.Image))
                {
                    throw new MvdException(MVD_MODULE_TYPE.MVD_MODUL_APP, MVD_ERROR_CODE.MVD_E_CALLORDER);
                }

                // 自动阈值模式下,不校验Rough和scale
                if (0 == Param.ScaleMode)
                {
                    double RoughScale = Convert.ToDouble(Param.ParamDouble["速度尺度"]);
                    double fineScale = Convert.ToDouble(Param.ParamInt["特征尺度"]);
                    if (fineScale > RoughScale)
                    {
                        throw new MvdException(MVD_MODULE_TYPE.MVD_MODUL_APP
                                             , MVD_ERROR_CODE.MVD_E_PARAMETER_ILLEGAL
                                             , "Fine scale must lower than Rough scale.");
                    }
                }
                HPFeaturePattern.InputImage = TrainImage;
                // region更新
                HPFeaturePattern.RegionList.Clear();
                var region = new CPatMatchRegion();
                ROI = LearnMatch.ROI;
                region.Shape = LearnMatch.ROI;
                region.Sign = true;
                HPFeaturePattern.RegionList.Add(region);
                Param.UpdatePatCreateParas(HPFeaturePattern);

                //   HPFeaturePattern.BasicParam.FixPoint =  new MVD_POINT_F(LearnMatch.cMvdPoint.GetPoint(0).fX, LearnMatch.cMvdPoint.GetPoint(0).fY);
                _StopWatch.Restart();
                HPFeaturePattern.Train();
                _StopWatch.Stop();

                var patternData = HPFeaturePattern.Result.Data;
                Param.ParamDouble["速度尺度"] = patternData.Rough;
                Param.ParamInt["特征尺度"] = Convert.ToInt32(patternData.Fine);
                Param.ParamInt["对比度阈值"] = patternData.LowThreshold;

                DisplayTrainedImageAndOutline(TemplateWindow);
                Logger.AddLog(matchingViewModel.ModuleParam.ModuleName + ":创建模板成功！");
            }
            catch (Exception ex)
            {
                Logger.GetExceptionMsg(ex);
            }
        }

        /// <summary>
        /// 展示模型图像和轮廓
        /// </summary>
        public void DisplayTrainedImageAndOutline(VMDisplayControl vMDisplay)
        {
            List<CPatMatchOutline> patmatchOutline = null;

            try
            {
                //清除上一次的模型结果
                vMDisplay.Clear();
                vMDisplay.MVDRender.ClearImages();
                if (null == HPFeaturePattern.Result)
                {
                    return;
                }

                // 空引用的话直接进Catch
                rTrainImage = HPFeaturePattern.Result.Data.TrainedImage;
                patmatchOutline = HPFeaturePattern.Result.OutlineList;
                ModelData = HPFeaturePattern.ModelData;
                ModelSize = HPFeaturePattern.ModelSize;
                if (null != rTrainImage)
                {

                    vMDisplay.Image = rTrainImage;
                    //同步刷新，避免图形显示偏移
                    vMDisplay.MVDRender.Display(MVDRenderActivex.MVD_REFRESH_MODE.Sync);
                    _PatternOutlineList.Clear();
                }

                if (null != patmatchOutline)
                {
                    foreach (var item in patmatchOutline)
                    {
                        CMvdPointSetF pointSetG = new CMvdPointSetF();
                        CMvdPointSetF pointSetY = new CMvdPointSetF();
                        CMvdPointSetF pointSetR = new CMvdPointSetF();

                        foreach (var point in item.EdgePointList)
                        {
                            if (0 == point.Score)
                            {
                                pointSetG.AddPoint(point.Position.fX, point.Position.fY);
                            }
                            else if (1 == point.Score)
                            {
                                pointSetY.AddPoint(point.Position.fX, point.Position.fY);
                            }
                            else if (2 == point.Score)
                            {
                                pointSetR.AddPoint(point.Position.fX, point.Position.fY);
                            }
                        }

                        pointSetG.BorderColor = new MVD_COLOR(0, 255, 0, 255);
                        pointSetY.BorderColor = new MVD_COLOR(255, 255, 0, 255);
                        pointSetR.BorderColor = new MVD_COLOR(255, 0, 0, 255);

                        if (0 != pointSetG.PointsList.Count)
                        {
                            vMDisplay.AddShape(pointSetG);
                        }

                        if (0 != pointSetY.PointsList.Count)
                        {
                            vMDisplay.AddShape(pointSetY);
                        }

                        if (0 != pointSetR.PointsList.Count)
                        {
                            vMDisplay.AddShape(pointSetR);
                        }

                        _PatternOutlineList.Add(pointSetG);
                        _PatternOutlineList.Add(pointSetY);
                        _PatternOutlineList.Add(pointSetR);
                    }
                }
            }
            catch (MvdException ex)
            {
                //Logger.Log("Display trained image and outline catch mvd exception, error code is : 0x" + ex.ErrorCode.ToString("X") + ".\r\n");
            }
            catch (System.Exception ex)
            {
                //Logger.Log("Display Trained Image and outline catch ex, ex is : " + ex.Message + ", Stack trace is : " + ex.StackTrace + ".\r\n");
            }
            finally
            {
                vMDisplay.MVDRender.Display();
            }
        }

        #endregion
        #region IDisposable Implementation
        public void Dispose()
        {
            // Dispose managed resources
            _StopWatch?.Stop();
            _StopWatch = null;
            LocalImage?.Dispose();
            TrainImage?.Dispose();
            LearnMatch?.Dispose();
            TemplateWindow?.Dispose();

            // Set large fields to null
            matchingViewModel = null;
            view = null;
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}
